﻿
/* $Id: NetClient.cs 7 2011-03-31 12:52:56Z nramsbottom@gmail.com $ */

using System;
using System.Net.Sockets;

namespace SimpleNetServer
{

	delegate void NetClientDisconnected(NetClient client);

	class NetClient
	{

		public bool LoggedIn { get; set; }

		private Socket _sck;
		
		// stores all incoming data up to a configured limit. if a packet is not identified
		// before this buffer is filled then the client is disconnected and the data discarded.
		private NetBuffer _packetBuffer;
		private byte[] _receiveBuffer;
		private AsyncCallback _endReceiveCallback = null;

		public event NetClientDisconnected Disconnected;

		public NetClient(Socket sck)
		{
			_sck = sck;
			_packetBuffer = new NetBuffer(1024); // we'll cache up to 1024 bytes of data
			_receiveBuffer = new byte[32];
			_endReceiveCallback = new AsyncCallback(EndReceive);

			BeginReceive();

		} //

		public void Disconnect()
		{
			_sck.Close();
		} //

		private void BeginReceive()
		{
			_sck.BeginReceive(_receiveBuffer, 0, _receiveBuffer.Length, SocketFlags.None, _endReceiveCallback, null);
		} //

		private void EndReceive(IAsyncResult ar)
		{
			int bytes = 0;
			try
			{
				bytes = _sck.EndReceive(ar);
			}
			catch (Exception ex)
			{
				System.Diagnostics.Debug.WriteLine(ex);
				bytes = 0;
			}
			
			if (bytes == 0)
			{
				if (this.Disconnected != null)
					this.Disconnected(this);
				return;
			}

			if (_packetBuffer.HasCapacity(bytes))
			{
				_packetBuffer.Write(_receiveBuffer, 0, bytes);

				// scan through the packet buffer and handle any complete packets.
				HandlePackets();

				BeginReceive();
			}
			else
			{
				// packet buffer cannot store any more data.
				System.Diagnostics.Debug.WriteLine("Packet buffer overflow.");
				_sck.Close();
				if (this.Disconnected != null)
					this.Disconnected(this);
			}

		} //

		private void HandlePackets()
		{
			if (this._packetBuffer.Size == 0)
				return;

			while (this._packetBuffer.Size >= 4)
			{

				UInt32 typeId = BitConverter.ToUInt32(this._packetBuffer.Peek(4), 0);

				var handler = PacketHandlers.GetHandler(typeId);

				if (handler != null)
				{
					// are there enough bytes to allow us to read the 
					// packet identifier and the packet data?
					if (this._packetBuffer.Size >= 4 + handler.Length)
					{

						this._packetBuffer.Read(4); // discard the identifier

						var packetData = this._packetBuffer.Read(handler.Length);

						handler.OnReceive(this, new PacketReader(packetData, handler.Length));

					}
					else
						break; // break from loop
				}
				else
				{
					// discard
					this._packetBuffer.Read(4);
					Console.WriteLine("No packet handler found for {0}", typeId);
					break;
				}
			}

		} //
		
		public void Send(NetPacket packet)
		{
			this._sck.Send(packet.GetData());
		} //

	} // class

} // namespace
